#include "zoo.h"
#include <cstdlib>
#include <ctime>
Money::Money()
{
	totalincome = 0;
}
Money::Money(const double &m):totalincome(m){}
Money Money::operator+(const double& m)
{
	return Money(totalincome + m);
}
Money Money::operator-(const double& m)
{
	return Money(totalincome - m);
}
Money Money::operator+(const Money& other)
{
	return(totalincome + other.totalincome);
}
Money Money::operator-(const Money& other)
{
	return(totalincome - other.totalincome);
}
double Money::getmoney()
{
	return totalincome;
}
AnimalFood::AnimalFood()
{
	type = "0";
	amount = 0;
}
AnimalFood::AnimalFood(const string nameoftype, const int eamount)
{
	type = nameoftype;
	amount = eamount;
}
void AnimalFood::setamount(const int eamount)
{
	amount = eamount;
}
void AnimalFood::reduceamount(int r)
{
	amount -= r;
}
void AnimalFood::settype(const string nameoftype)
{
	type = nameoftype;
}
string AnimalFood::gettype()
{
	return type;
}
int AnimalFood::getamount()
{
	return amount;
}
AnimalEnclosure::AnimalEnclosure()
{
	dirtlevel = 0;
	curstatus = 1;
}
void AnimalEnclosure::adddirlevel(const double m)
{
	dirtlevel += m;
}
bool AnimalEnclosure::isclosed()
{
	return !curstatus;
}
void AnimalEnclosure::open()
{
	curstatus = 1;
}
void AnimalEnclosure::close()
{
	curstatus = 0;
}
void AnimalEnclosure::resetdir()
{
	dirtlevel = 0;
}
double AnimalEnclosure::getdirtlevel()
{
	return dirtlevel;
}
bool AnimalEnclosure::getcurstatus()
{
	return curstatus;
}
Animal::Animal() { weight = 0; eatenfoodnum = 0; }
Animal::Animal(const double &w)
{
	weight = w;
	eatenfoodnum = 0;
}
double Animal::getfoodeaten()
{
	return eatenfoodnum;
}
void Animal::resetfoodeaten()
{
	eatenfoodnum = 0;
}
Elephant::Elephant()
{
	Animal();
	trunklength = 0;
}
Elephant::Elephant(const double &we,const double &t):Animal(we)
{
	trunklength = t;
}
void Elephant::eat(AnimalFood& food)
{
	if (food.gettype() == "peanut")
	{
		eatenfoodnum += food.getamount();
	}
}
Giraffe::Giraffe()
{
	Animal();
	necklength = 0;
}
Giraffe::Giraffe(const double& wg, const double& n):Animal(wg)
{
	necklength = n;
}
void Giraffe::eat(AnimalFood& food)
{
	if (food.gettype() == "carrot")
	{
		eatenfoodnum += food.getamount();
	}
}
Monkey::Monkey()
{
	Animal();
	armlength = 0;
}
Monkey::Monkey(const double &wm, const double &a):Animal(wm)
{
	armlength = a;
}
void Monkey::eat(AnimalFood& food)
{
	if (food.gettype() == "banana")
	{
		eatenfoodnum += food.getamount();
	}
}
Person::Person()
{
	name = "0";
	age = 0;
}
Person::Person(const string ownname, const int ownage):name(ownname),age(ownage){}
ZooKeeper::ZooKeeper()
{
	Person();
	totalcleaningday = 0;
}
ZooKeeper::ZooKeeper(const string ownname, const int ownage)
	:Person(ownname, ownage), totalcleaningday(0){}
void ZooKeeper::addtotalcleaningday()
{
	totalcleaningday++;
}
int ZooKeeper::gettotalcleaningday()
{
	return totalcleaningday;
}
FoodSeller::FoodSeller(string ownname, int ownage)
	:Person(ownname,ownage),foodincome(0)
{
	sellfood.push_back(AnimalFood("peanut", 10000));
	sellfood.push_back(AnimalFood("carrot", 7000));
	sellfood.push_back(AnimalFood("banana", 4000));
}
bool FoodSeller::Sellfood(const string& n,const int &quantity,const double &payment)
{
	for (auto& food : sellfood) {
		if (food.gettype() ==n && food.getamount() >= quantity) {
			food.reduceamount(quantity);
			foodincome=foodincome+payment;
			return true;
		}
	}
	return false;
}
double FoodSeller::getincomeoffood()
{
	return foodincome.getmoney();
}
bool FoodSeller::avail(const string& n)
{
	for (auto& f : sellfood)
	{
		if (f.gettype() == n)
		{
			if (f.getamount() > 0)return 1;
			else return 0;
		}
	}
}
Visitor::Visitor()
{
	Person();
	passid = 0;
}
Visitor::Visitor(const string& n, const int& a, const int& p):Person(n,a),passid(p){}
Child::Child(const string& n, const int& a, const int& p):Visitor(n,a,p){}
void Child::addfood(AnimalFood& add)
{
	childhas.push_back(add);
}
void Child::feed(Animal *a)
{
	for (auto& f : childhas)
	{
		a->eat(f);
	}
}
Adult::Adult(const string& n, const int& a, const int& p,const int &cn):Visitor(n,a,p)
{
	childnum = cn;
	ownmoney = rand() % 11 + 10;
	for (int i = 0; i < childnum; i++)
	{
		accompany.push_back(Child());
	}
}
void Adult::payforpass(Money &income)
{
	double c= 1 + 0.4 * childnum;
	income = income + c;
	ownmoney -= c;
}
void Adult::payforfood(FoodSeller &f)
{
	double aver = ownmoney / 3;
	double num1 = aver / 0.2;
	int n1 = num1;
	double num2 = aver / 0.3;
	int n2 = num2;
	double num3 = aver / 0.5;
	int n3 = num3;
	if (f.Sellfood("peanut", n1, n1 * 0.2))
	{
		if (f.Sellfood("carrot", n2, n2 * 0.3))
		{
			if (f.Sellfood("banana", n3, n3 * 0.5))
			{
				AnimalFood p("peanut", n1);
				AnimalFood c("carrot", n2);
				AnimalFood b("banana", n3);
				for (int i = 0; i < childnum; i++)
				{
					accompany[i].addfood(p);
					accompany[i].addfood(c);
					accompany[i].addfood(b);
				}
			}
		}
	}
}
Zoo::Zoo() : zookeeper("Keeper", 30), foodseller("Seller", 25), totalrunday(0), totalnumofadult(0), totalnumofchild(0),income(0)
{
	animalenclosureclose[0] = 0;
	animalenclosureclose[1] = 0;
	animalenclosureclose[2] = 0;
	animals.push_back(new Elephant(5000, 2.5));
	animals.push_back(new Giraffe(1500, 2.0));
	animals.push_back(new Giraffe(1400, 1.9));
	animals.push_back(new Monkey(50, 0.5));
	animals.push_back(new Monkey(45, 0.45));
	animals.push_back(new Monkey(40, 0.4));
	animalenclosures.resize(3);
}
void Zoo::runaday()
{
	totalrunday+=1;
	int adultnum = rand() % 21 + 20;
	totalnumofadult += adultnum;
	for (int i = 0; i < adultnum; i++)
	{
		int childnum = rand() % 3 + 1;
		totalnumofchild += childnum;
		Adult a("Ad", 30, i, childnum);
		a.payforpass(income);
		a.payforfood(foodseller);
		for (int j = 0; j < childnum; j++)
		{
			a.accompany[j].feed(animals[0]);
			a.accompany[j].feed(animals[rand()%1+1]);
			a.accompany[j].feed(animals[rand()%2+3]);
		}
	}
	animalenclosures[0].adddirlevel(animals[0]->getfoodeaten());
	animalenclosures[1].adddirlevel(animals[1]->getfoodeaten());
	animalenclosures[1].adddirlevel(animals[2]->getfoodeaten());
	animalenclosures[2].adddirlevel(animals[3]->getfoodeaten());
	animalenclosures[2].adddirlevel(animals[4]->getfoodeaten());
	animalenclosures[2].adddirlevel(animals[5]->getfoodeaten());
	for (size_t i = 0; i < animals.size(); ++i) 
	{
			animals[i]->resetfoodeaten();
	}
	for (size_t i = 0; i < animalenclosures.size(); ++i)
	{
		if (animalenclosures[i].isclosed())
		{
			animalenclosures[i].open();
			animalenclosures[i].resetdir();
		}
	}
	for (size_t i = 0; i < animalenclosures.size(); ++i)
	{
		if (animalenclosures[i].getdirtlevel() > 2000)
		{
			animalenclosures[i].close();
			animalenclosureclose[i]++;
			zookeeper.addtotalcleaningday();
			break;
		}
	}
}
void Zoo::run()
{
	while (foodseller.avail("peanut") &&
		foodseller.avail("carrot") &&
		foodseller.avail("banana") &&
		zookeeper.gettotalcleaningday() < 10)
	{
		runaday();
	}
	std::cout << "Zoo closed after " << totalrunday << " days.\n";
	if (zookeeper.gettotalcleaningday() >= 10) 
	{
		std::cout << "The zoo closed because the zoo keeper had enough of cleaning and quit!\n";
	}
	else if (!foodseller.avail("peanut")) 
	{
		std::cout << "The zoo closed because the seller ran out of peanuts.\n";
	}
	else if (!foodseller.avail("carrot")) 
	{
		std::cout << "The zoo closed because the seller ran out of carrots.\n";
	}
	else if (!foodseller.avail("banana")) 
	{
		std::cout << "The zoo closed because the seller ran out of bananas.\n";
	}
	std::cout << "Total adults: " << totalnumofadult << "\n";
	std::cout << "Total children: " << totalnumofchild << "\n";
	std::cout << "Seller's total money: $" << foodseller.getincomeoffood() << "\n";
	std::cout << "Days zoo keeper spent cleaning: " << zookeeper.gettotalcleaningday() << "\n";
	std::cout << "The number of days elephant enclosure was:" << animalenclosureclose[0]<<'\n';
	std::cout << "The number of days giraffe enclosure was:" << animalenclosureclose[1] << '\n';
	std::cout << "The number of days monkey enclosure was:" << animalenclosureclose[2] << '\n';
}
Zoo::~Zoo()
{
	for (auto* a : animals)
	{
		delete a;
	}
}




